
package com.joolun.cloud.mall.admin.service.impl;

import cn.hutool.core.util.StrUtil;
import com.alipay.easysdk.payment.common.models.AlipayTradeFastpayRefundQueryResponse;
import com.alipay.easysdk.payment.common.models.AlipayTradeRefundResponse;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.joolun.cloud.common.core.constant.CommonConstants;
import com.joolun.cloud.common.core.constant.SecurityConstants;
import com.joolun.cloud.common.core.util.R;
import com.joolun.cloud.mall.admin.service.*;
import com.joolun.cloud.mall.common.config.MallConfigProperties;
import com.joolun.cloud.mall.common.constant.MallConstants;
import com.joolun.cloud.mall.common.entity.*;
import com.joolun.cloud.mall.admin.mapper.OrderRefundsMapper;
import com.joolun.cloud.mall.common.enums.OrderInfoEnum;
import com.joolun.cloud.mall.common.enums.OrderItemEnum;
import com.joolun.cloud.mall.common.enums.OrderRefundsEnum;
import com.joolun.cloud.mall.common.feign.FeignJooLunPayService;
import com.joolun.cloud.pay.common.constant.PayConstants;
import com.joolun.cloud.pay.common.dto.AliBaseRequest;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * 退款详情
 *
 * @author www.joolun.com
 * @date 2019-11-14 16:35:25
 */
@Slf4j
@Service
@AllArgsConstructor
public class OrderRefundsServiceImpl extends ServiceImpl<OrderRefundsMapper, OrderRefunds> implements OrderRefundsService {

	private final OrderItemService orderItemService;
	private final OrderInfoService orderInfoService;
	private final FeignJooLunPayService feignJooLunPayService;
	private final MallConfigProperties mallConfigProperties;
	private final PointsRecordService pointsRecordService;
	private final UserInfoService userInfoService;
	private final ShopInfoService shopInfoService;
	private final DistributionOrderService distributionOrderService;
	private final DistributionOrderItemService distributionOrderItemService;
	private final DistributionUserService distributionUserService;
	private final GoodsSkuService goodsSkuService;
	private final SeckillInfoService seckillInfoService;

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean doOrderRefunds(OrderRefunds entity) {
		OrderRefunds orderRefunds = baseMapper.selectById(entity.getId());
		if(orderRefunds != null){
			if(OrderRefundsEnum.STATUS_11.getValue().equals(entity.getStatus()) || OrderRefundsEnum.STATUS_211.getValue().equals(entity.getStatus())){
				//查询该订单详情是否有赠送积分
				PointsRecord pointsRecord = new PointsRecord();
				pointsRecord.setRecordType(MallConstants.POINTS_RECORD_TYPE_2);
				pointsRecord.setOrderItemId(orderRefunds.getOrderItemId());
				pointsRecord = pointsRecordService.getOne(Wrappers.query(pointsRecord));
				if(pointsRecord !=null && StrUtil.isNotBlank(pointsRecord.getId())){
					UserInfo userInfo = userInfoService.getById(pointsRecord.getUserId());
					//校验用户当前积分是否够积分回滚
					if(userInfo.getPointsCurrent() < pointsRecord.getAmount()){
						throw new RuntimeException("该用户当前积分不够抵扣订单赠送的积分");
					}
				}

				//查询该订单是否有分销订单
				DistributionOrderItem distributionOrderItem = new DistributionOrderItem();
				distributionOrderItem.setOrderId(orderRefunds.getOrderId());
				distributionOrderItem.setOrderItemId(orderRefunds.getOrderItemId());
				List<DistributionOrderItem> listDistributionOrderItem = distributionOrderItemService.list(Wrappers.query(distributionOrderItem));
				if(listDistributionOrderItem != null && listDistributionOrderItem.size() > 0){
					listDistributionOrderItem.forEach(item -> {
						DistributionOrder distributionOrder = distributionOrderService.getById(item.getDistributionOrderId());
						if(MallConstants.DISTRIBUTION_COMMISSION_STATUS_2.equals(distributionOrder.getCommissionStatus())){
							//如果该订单下的分销订单已经解冻，则不能退款
							throw new RuntimeException("该订单关联的分销订单佣金已经解冻，不能退款");
						}
						BigDecimal itemCommission = item.getCommission();
						//回滚已返佣金
						item.setCommission(BigDecimal.ZERO);
						distributionOrderItemService.updateById(item);
						distributionOrderService.updateCommission(distributionOrder.getId(),itemCommission.negate());
						distributionUserService.updateCommissionTotal(distributionOrder.getDistributionUserId(),itemCommission.negate());
					});

				}
				if(orderRefunds.getRefundAmount().compareTo(BigDecimal.ZERO) > 0){//退款金额大于0
					OrderItem orderItem = orderItemService.getById2(orderRefunds.getOrderItemId());
					OrderInfo orderInfo = orderInfoService.getById(orderItem.getOrderId());
					//校验数据，只有已支付的订单、未退款的订单详情才能退款
					if(CommonConstants.YES.equals(orderInfo.getIsPay())
							&& CommonConstants.NO.equals(orderItem.getIsRefund())
							&& orderRefunds.getRefundAmount().compareTo(BigDecimal.ZERO) == 1){
						//获取支付总金额
						AtomicReference<BigDecimal> totalFee = new AtomicReference<>(BigDecimal.ZERO);
						List<OrderInfo> listOrderInfo = orderInfoService.list(Wrappers.<OrderInfo>query().lambda()
								.eq(OrderInfo::getTransactionId, orderInfo.getTransactionId()));
						listOrderInfo.forEach(orderInfo1 -> {
							totalFee.set(totalFee.get().add(orderInfo1.getPaymentPrice()));
						});
						ShopInfo shopInfo = shopInfoService.getById(orderInfo.getShopId());
						//发起微信退款申请
						if(MallConstants.ORDER_PAYMENT_TYPE_1.equals(orderInfo.getPaymentType())){
							WxPayRefundRequest request = new WxPayRefundRequest();
							request.setSubMchId(shopInfo.getWxMchId());
							request.setTransactionId(orderInfo.getTransactionId());
							request.setOutRefundNo(orderRefunds.getId());
							request.setTotalFee(totalFee.get().multiply(new BigDecimal(100)).intValue());
							request.setRefundFee(orderRefunds.getRefundAmount().multiply(new BigDecimal(100)).intValue());
							request.setNotifyUrl(mallConfigProperties.getNotifyHost()+"/mall/orderrefunds/notify-refunds");
							R<WxPayRefundResult> r = feignJooLunPayService.refundOrderWx(request, SecurityConstants.FROM_IN);
							if(r.isOk()){
								WxPayRefundResult wxPayRefundResult = r.getData();
								entity.setRefundTradeNo(wxPayRefundResult.getRefundId());
							}else{
								throw new RuntimeException(r.getMsg());
							}
						}
						//发起支付宝退款申请
						if(MallConstants.ORDER_PAYMENT_TYPE_2.equals(orderInfo.getPaymentType())){
							Map<String, Object> params = new HashMap<>();
							params.put("outTradeNo",orderInfo.getOrderNo());
							params.put("outRequestNo",orderRefunds.getId());
							params.put("refundAmount",orderRefunds.getRefundAmount().toString());
							AliBaseRequest aliBaseRequest = new AliBaseRequest();
							aliBaseRequest.setAppAuthToken(shopInfo.getAliAuthToken());
							aliBaseRequest.setParams(params);
							R<AlipayTradeRefundResponse> r = feignJooLunPayService.refundOrderAli(aliBaseRequest, SecurityConstants.FROM_IN);
							if(r.isOk()){
								entity.setRefundTradeNo(orderRefunds.getId());
							}else{
								throw new RuntimeException(r.getMsg());
							}
						}
					}
				}
			}else if(OrderRefundsEnum.STATUS_12.getValue().equals(entity.getStatus()) || OrderRefundsEnum.STATUS_22.getValue().equals(entity.getStatus())){
				//如果拒绝退款修改一下orderitem状态
				OrderItem orderItem = orderItemService.getById2(orderRefunds.getOrderItemId());
				orderItem.setStatus(OrderItemEnum.STATUS_0.getValue());
				orderItemService.updateById(orderItem);
			}
			//更新退款
			baseMapper.updateById(entity);
		}
		return Boolean.TRUE;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void doOrderRefundsResult(OrderRefunds orderRefunds) {
		//修改订单详情退款状态为已退款
		OrderItem orderItem = orderItemService.getById(orderRefunds.getOrderItemId());
		if((OrderRefundsEnum.STATUS_11.getValue().equals(orderRefunds.getStatus()) || OrderRefundsEnum.STATUS_211.getValue().equals(orderRefunds.getStatus()))
				&& CommonConstants.NO.equals(orderItem.getIsRefund())){
			orderItem.setIsRefund(CommonConstants.YES);
			String status = "";
			if(OrderRefundsEnum.STATUS_11.getValue().equals(orderRefunds.getStatus())){
				status = OrderItemEnum.STATUS_3.getValue();
			}
			if(OrderRefundsEnum.STATUS_211.getValue().equals(orderRefunds.getStatus())){
				status = OrderItemEnum.STATUS_4.getValue();
			}
			orderItem.setStatus(status);
			orderItemService.updateById(orderItem);
			baseMapper.updateById(orderRefunds);

			//回滚库存
			GoodsSku goodsSku = goodsSkuService.getById(orderItem.getSkuId());
			if(goodsSku != null){
				goodsSku.setStock(goodsSku.getStock() + orderItem.getQuantity());
				goodsSkuService.updateById(goodsSku);
			}
			//回滚赠送积分
			PointsRecord pointsRecord = new PointsRecord();
			pointsRecord.setRecordType(MallConstants.POINTS_RECORD_TYPE_2);
			pointsRecord.setOrderItemId(orderItem.getId());
			pointsRecord = pointsRecordService.getOne(Wrappers.query(pointsRecord));
			OrderInfo orderInfo = orderInfoService.getById(orderItem.getOrderId());
			//查询该订单详情是否有赠送积分
			if(pointsRecord !=null && StrUtil.isNotBlank(pointsRecord.getId())){
				//减回赠送的积分
				pointsRecord.setId(null);
				pointsRecord.setTenantId(null);
				pointsRecord.setCreateTime(null);
				pointsRecord.setUpdateTime(null);
				pointsRecord.setShopId(goodsSku.getShopId());
				pointsRecord.setDescription("【退款】 " + pointsRecord.getDescription());
				pointsRecord.setAmount(-pointsRecord.getAmount());
				pointsRecord.setRecordType(MallConstants.POINTS_RECORD_TYPE_3);
				//新增积分记录
				pointsRecordService.save(pointsRecord);
				//减去赠送积分
				userInfoService.updatePoints(orderInfo.getUserId(),pointsRecord.getAmount());
			}

			//回滚抵扣积分
			PointsRecord pointsRecord2 = new PointsRecord();
			pointsRecord2.setRecordType(MallConstants.POINTS_RECORD_TYPE_4);
			pointsRecord2.setOrderItemId(orderItem.getId());
			pointsRecord2 = pointsRecordService.getOne(Wrappers.query(pointsRecord2));
			//查询该订单详情是否有抵扣积分
			if(pointsRecord2 !=null && StrUtil.isNotBlank(pointsRecord2.getId())){
				//减回赠送的积分
				pointsRecord2.setId(null);
				pointsRecord2.setTenantId(null);
				pointsRecord2.setCreateTime(null);
				pointsRecord2.setUpdateTime(null);
				pointsRecord2.setShopId(goodsSku.getShopId());
				pointsRecord2.setDescription("【退款】 " + pointsRecord2.getDescription());
				pointsRecord2.setAmount(-pointsRecord2.getAmount());
				pointsRecord2.setRecordType(MallConstants.POINTS_RECORD_TYPE_6);
				//新增积分记录
				pointsRecordService.save(pointsRecord2);
				//减去赠送积分
				userInfoService.updatePoints(orderInfo.getUserId(),pointsRecord2.getAmount());
			}

			//回滚秒杀已售数量
			if(MallConstants.ORDER_TYPE_3.equals(orderInfo.getOrderType())){
				SeckillInfo seckillInfo = seckillInfoService.getById(orderInfo.getMarketId());
				seckillInfo.setSeckillNum(seckillInfo.getSeckillNum()-1);
				if(!seckillInfoService.updateById(seckillInfo)){//更新秒杀已售数量
					throw new RuntimeException("请重新提交");
				}
			}

			List<OrderItem> listOrderItem = orderItemService.list(Wrappers.<OrderItem>query().lambda()
					.eq(OrderItem::getOrderId,orderItem.getOrderId()));
			List<OrderItem> listOrderItem2 = listOrderItem.stream()
					.filter(obj -> !obj.getId().equals(orderRefunds.getOrderItemId()) && CommonConstants.NO.equals(obj.getIsRefund())).collect(Collectors.toList());
			//如果订单下面所有订单详情都退款了，则取消订单
			if(listOrderItem2.size() <= 0){
				orderInfo = new OrderInfo();
				orderInfo.setId(orderItem.getOrderId());
				orderInfo.setStatus(OrderInfoEnum.STATUS_5.getValue());
				orderInfoService.updateById(orderInfo);
			}
		}
	}

	@Override
	public IPage<OrderRefunds> page1(IPage<OrderRefunds> page, OrderRefunds orderRefunds) {
		return baseMapper.selectPage1(page,orderRefunds);
	}
}
